package store;

import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
import dataview.CriterioRicerca;
import dataview.Menus;
import dataview.Ordinamento;
import dataview.PerStringa;
import dataview.PerTermine;
import exceptions.DBException;
import exceptions.ElementoNonPresente;
import exceptions.NomeGiaInUso;

public class TuttiMenu extends BaseStore {
	private static TuttiMenu singleton;
	private CriterioRicerca ultimaRicerca;
	private ValutazioniMenuAttive valAttive;
	
	private TuttiMenu() {

	}
	
	public static TuttiMenu getTuttiMenu() {
		if (singleton == null){
			singleton = new TuttiMenu();
			singleton.ultimaRicerca = BaseStore.getSettingsMenu();
		}
		return singleton;
	}
	
	public boolean presente(String menu) throws DBException {
		try {
			getMenuElement(menu);
		} catch (ElementoNonPresente e) {
			return false;
		}
		return true;
	}
	
	public boolean usatoCibo(Cibo cibo) throws DBException {
		try {
			return (Element)XPath.selectSingleNode(getDB(), "/easycooking/menus/menu/portate/portata_cibo[cibo='" + cibo.getNome() + "']") != null || (Element)XPath.selectSingleNode(getDB(), "/easycooking/menus/menu/portate/portata_bevanda[cibo='" + cibo.getNome() + "']") != null;
		} catch (Exception e) {
			throw new DBException(e);
		}
	}
	
	public boolean usataRicetta(Ricetta ricetta) throws DBException {
		try {
			return (Element)XPath.selectSingleNode(getDB(), "/easycooking/menus/menu/portate/portata_piatto[ricetta='" + ricetta.getNome() + "']") != null;
		} catch (Exception e) {
			throw new DBException(e);
		}
	}
	
	/**
	 * Restituisce l'insieme di tutti i menu salvati nel database
	 * 
	 * @throws DBException
	 */
	public Menus tuttiMenu() throws DBException {
		try {
			Set<Menu> menus = new TreeSet<Menu>(Menu.getComparator(true));
			for (Object menu : XPath.selectNodes(getDB(), "/easycooking/menus/menu"))
				menus.add(Menu.fromXml((Element)menu, true));
			return new Menus(menus);
		} catch (Exception e) {
			throw new DBException(e);
		}
	}
	
	public Menus ricercare(CriterioRicerca criterio) throws DBException {
		if (criterio == null) return new Menus();
		setSettingsRicette(criterio);
		ultimaRicerca = criterio;
		SortedSet<Menu> menus = new TreeSet<Menu>(Menu.getComparator(criterio.getOrdinamento() == Ordinamento.crescente));
		Menus mm = tuttiMenu();
		
		//XXX: quali sono le parti che devo andare a guardare??? Io ho pensato al nome, alle note e alla presentazione
		if (criterio instanceof PerStringa) {
			PerStringa c = (PerStringa)criterio;
			for (Menu menu : mm)
				if (menu.getNome().contains(c.getStringa()) || menu.getInfo().getNote().contains(c.getStringa()) || menu.getInfo().getPresentazione().contains(c.getStringa())) {
					if (c.getAppare()) menus.add(menu);
				} else if (!c.getAppare()) menus.add(menu);
		}
		
		if (criterio instanceof PerTermine) {
			PerTermine c = (PerTermine)criterio;
			if (c.getEun()) {
				for (Menu menu : mm)
					if (menu.getTag() != null) for (Termine termine : menu.getTag())
						if (termine.diTipo(c.getTermine())) {
							menus.add(menu);
							break;
						}
			} else {
				for (Menu menu : mm) {
					menus.add(menu);
					if (menu.getTag() != null) for (Termine termine : menu.getTag())
						if (termine.diTipo(c.getTermine())) {
							menus.remove(menu);
							break;
						}
				}
			}
		}
		
		return new Menus(menus);
	}
	
	public Menus ultimiCercati() throws DBException {
		return ricercare(ultimaRicerca);
	}
	
	public void inserire(Menu menu) throws DBException, NomeGiaInUso {
		inserire(menu, true);
	}
	
	private void inserire(Menu menu, boolean save) throws DBException, NomeGiaInUso {
		if (presente(menu.getNome())) throw new NomeGiaInUso("Nel database e' gia' presente un menu con nome = '" + menu.getNome() + "'");
		getDB().getRootElement().getChild("menus").addContent(menu.toXml());
		if (save) save(false);
	}
	
	public void inserisciMenu(Menus menu) throws DBException, NomeGiaInUso {
		for (Menu m : menu) {
			while (presente(m.getNome()))
				m.setNome(m.getNome() + "X");
			inserire(m, false);
		}
	}
	
	public void elimina(Menu menu) throws DBException, ElementoNonPresente {
		if (!presente(menu.getNome())) throw new ElementoNonPresente("Nel database non e' presente un menu con nome = '" + menu.getNome() + "'");
		getDB().getRootElement().getChild("menus").removeContent(getMenuElement(menu.getNome()));
		save(false);
	}
	
	public ValutazioniMenuAttive valutazioniAttive() throws DBException {
		if (valAttive == null) valAttive = getSettingsValutazioneMenu();
		return valAttive;
	}
	
	public void modificaValutazioniAttive(ValutazioniMenuAttive valutazioniAttive) throws DBException {
		if (valutazioniAttive == null) return;
		valAttive = valutazioniAttive;
		setSettingsValutazioneMenu(valutazioniAttive);
	}
	
	/**
	 * Restituisce l'elemento che rappresenta il menu richiesto
	 * 
	 * @param nome Il nome del menu da cercare
	 * @return L'elemento che rappresenta il menu dal nome passato come parametro
	 * @throws ElementoNonPresente sse non e' presente un menu con il nome richiesto
	 * @throws DBException
	 */
	protected Element getMenuElement(String nome) throws ElementoNonPresente, DBException {
		Element menu = null;
		try {
			menu = (Element)XPath.selectSingleNode(getDB(), "/easycooking/menus/menu[@nome='" + nome + "']");
		} catch (JDOMException e) {
			throw new DBException(e);
		}
		if (menu == null) throw new ElementoNonPresente("Nel database non e' presente un menu con nome = '" + nome + "'");
		return menu;
	}
}
